using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using CHEnhanceEfCore.System;
using Microsoft.Extensions.DependencyInjection;
using Quartz;

namespace CHEnhanceEfCore.Config.Schedule.config
{
    public class QuartzConfigFactory : IDisposable
    {
        private readonly IScheduler _scheduler;
        private readonly AppSettings _appSettings;
        private readonly IServiceProvider _serviceProvider;
        private readonly List<JobKey> _jobKeys = new();

        public QuartzConfigFactory(ISchedulerFactory schedulerFactory, QuartzJobFactory quartzJobFactory,
            AppSettings appSettings, IServiceProvider serviceProvider)
        {
            _appSettings = appSettings;
            _serviceProvider = serviceProvider;
            _scheduler = schedulerFactory.GetScheduler().Result;
            _scheduler.JobFactory = quartzJobFactory;
        }

        private IServiceScope getScope()
        {
            return _serviceProvider.CreateScope();
        }

        private List<QuartzJobConfig> getJobConfigs()
        {
            return _appSettings.jobConfigs;
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public async Task init()
        {
            string msg = "******init ScheduleService start******";
            Console.WriteLine(msg);
            //获取配置
            List<QuartzJobConfig> jobConfigs = getJobConfigs();
            //获取临时有效的作用域
            using var scope = getScope();
            //扫描jobs
            var jobTypes = scanJobTypes();
            //未有jobs
            if (jobTypes.Count == 0)
            {
                msg = "******init ScheduleService fail******:reason:no jobs";
                Console.WriteLine(msg);
                return;
            }

            //启动任务调度
            await _scheduler.Start();
            //任务调度
            await addSchedulingJobs(jobTypes, jobConfigs);

            msg = $"******init ScheduleService end******:total===>{_jobKeys.Count}";
            Console.WriteLine(msg);
        }

        /// <summary>
        /// 执行任务调度的配置初始化
        /// </summary>
        /// <param name="jobTypes"></param>
        /// <param name="jobConfigs"></param>
        private async Task addSchedulingJobs(IEnumerable<Type> jobTypes, List<QuartzJobConfig> jobConfigs)
        {
            foreach (var jobType in jobTypes)
            {
                QuartzJobAttribute quartzJobAttribute =
                    (QuartzJobAttribute) global::System.Attribute.GetCustomAttribute(jobType,
                        typeof(QuartzJobAttribute));
                if (null == quartzJobAttribute)
                {
                    //未使用注解 实现了IJob接口 采取默认配置方式 
                    //获取类名
                    string className = jobType.Name;
                    Console.WriteLine(
                        $"can not start that job: {className}, without QuartzJob name like: [QuartzJob(\"hello\")]");
                }
                else
                {
                    string jobName = quartzJobAttribute.name;
                    //根据name匹配config
                    var scheduleJobConfig = jobConfigs.FirstOrDefault(c => c.name.Equals(jobName));
                    //scheduleJobConfig不为空且状态是未被禁用
                    if (scheduleJobConfig is {disabled: false})
                    {
                        var name = scheduleJobConfig.name;
                        var jobKey = JobKey.Create(name);
                        var cron = scheduleJobConfig.cron;
                        await addJob(jobType, jobKey, cron);
                    }
                }
            }
        }

        /// <summary>
        /// 扫描IJob的实现类
        /// </summary>
        /// <returns></returns>
        private static List<Type> scanJobTypes()
        {
            // 获取当前程序集
            Assembly assembly = Assembly.GetExecutingAssembly();
            //扫描IJob的子类
            var jobTypes = assembly.GetTypes().Where(t => typeof(IJob).IsAssignableFrom(t)
                                                          && t.IsClass
                                                          && !t.IsAbstract);

            return jobTypes.ToList();
        }

        /// <summary>
        /// addJob
        /// </summary>
        /// <param name="jobType"></param>
        /// <param name="jobKey"></param>
        /// <param name="cron"></param>
        public async Task addJob(Type jobType, JobKey jobKey, string cron)
        {
            string msg = $"add job:{jobKey.Group},{jobKey.Name}";
            Console.WriteLine(msg);

            //IJobDetail是对任务的详细描述
            IJobDetail jobDetail = JobBuilder.Create(jobType)
                .WithIdentity(jobKey)
                .Build();
            //触发器
            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity(jobKey.Name)
                .StartNow()
                .WithCronSchedule(cron)
                .Build();
            //jobDetail与trigger绑定
            await _scheduler.ScheduleJob(jobDetail, trigger);

            //addToList
            _jobKeys.Add(jobKey);
        }

        /// <summary>
        /// 程序结束 释放资源
        /// </summary>
        public async void Dispose()
        {
            foreach (var jobKey in _jobKeys)
            {
                TriggerKey triggerKey = new TriggerKey(jobKey.Name, jobKey.Group);
                await _scheduler.PauseJob(jobKey); // 停止触发器
                await _scheduler.UnscheduleJob(triggerKey); // 移除触发器
                string msg = $"delete job:{jobKey.Group},{jobKey.Name}";
                Console.WriteLine(msg);
                await _scheduler.DeleteJob(jobKey); //删除任务
            }
        }
    }
}